<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>JavaScript面向对象精要读书笔记 - vzvixb</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="even" /><meta name="description" content="JavaScript（ES5）的面向对象精要 1.原始类型和引用类型 1.1 什么是类型 原始类型 保存为简单数据值。 引用类型 保存为对象，其本质是指向内存" /><meta name="keywords" content="Hugo, theme, even" />






<meta name="generator" content="Hugo 0.90.1 with theme even" />


<link rel="canonical" href="https://zhouxiaoxin.gitee.io/post/javascript/javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%B2%BE%E8%A6%81%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<link href="/sass/main.min.32d4dc642fec98c34c80bebb9c784c50771712b4a8a25d9f4dd9cce3534b426e.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="JavaScript面向对象精要读书笔记" />
<meta property="og:description" content="JavaScript（ES5）的面向对象精要 1.原始类型和引用类型 1.1 什么是类型 原始类型 保存为简单数据值。 引用类型 保存为对象，其本质是指向内存" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://zhouxiaoxin.gitee.io/post/javascript/javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%B2%BE%E8%A6%81%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2017-08-12T21:29:06+00:00" />
<meta property="article:modified_time" content="2017-08-12T21:29:06+00:00" />

<meta itemprop="name" content="JavaScript面向对象精要读书笔记">
<meta itemprop="description" content="JavaScript（ES5）的面向对象精要 1.原始类型和引用类型 1.1 什么是类型 原始类型 保存为简单数据值。 引用类型 保存为对象，其本质是指向内存"><meta itemprop="datePublished" content="2017-08-12T21:29:06+00:00" />
<meta itemprop="dateModified" content="2017-08-12T21:29:06+00:00" />
<meta itemprop="wordCount" content="13912">
<meta itemprop="keywords" content="读书笔记," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="JavaScript面向对象精要读书笔记"/>
<meta name="twitter:description" content="JavaScript（ES5）的面向对象精要 1.原始类型和引用类型 1.1 什么是类型 原始类型 保存为简单数据值。 引用类型 保存为对象，其本质是指向内存"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">Even</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">Home</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">Archs</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">Tags</li>
      </a><a href="/categories/">
        <li class="mobile-menu-item">Cates</li>
      </a><a href="/about/">
        <li class="mobile-menu-item">About</li>
      </a><a href="/pages/runoob/">
        <li class="mobile-menu-item">runoob</li>
      </a><a href="/pages/98wubi/">
        <li class="mobile-menu-item">98wubi</li>
      </a>
  </ul>
</nav>
  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">Even</a>
</div>

<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">Home</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">Archs</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">Tags</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/categories/">Cates</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/">About</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/pages/runoob/">runoob</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/pages/98wubi/">98wubi</a>
      </li>
  </ul>
</nav>
    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">JavaScript面向对象精要读书笔记</h1>

      <div class="post-meta">
        <span class="post-time"> 2017-08-12 </span>
        <div class="post-category">
            <a href="/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"> 读书笔记 </a>
            </div>
          <span class="more-meta"> 约 13912 字 </span>
          <span class="more-meta"> 预计阅读 28 分钟 </span>
        <span id="busuanzi_container_page_pv" class="more-meta"> <span id="busuanzi_value_page_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次阅读 </span>
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content">
    <nav id="TableOfContents">
  <ul>
    <li><a href="#1原始类型和引用类型">1.原始类型和引用类型</a>
      <ul>
        <li><a href="#11-什么是类型">1.1 什么是类型</a></li>
        <li><a href="#12-原始类型">1.2 原始类型</a></li>
        <li><a href="#13-引用类型">1.3 引用类型</a></li>
        <li><a href="#14-内建类型实例化">1.4 内建类型实例化</a></li>
        <li><a href="#15-访问属性">1.5 访问属性</a></li>
        <li><a href="#16-鉴别引用类型">1.6 鉴别引用类型</a></li>
        <li><a href="#18-原始封装类型">1.8 原始封装类型</a></li>
        <li><a href="#19-总结">1.9 总结</a></li>
      </ul>
    </li>
    <li><a href="#2-函数">2. 函数</a>
      <ul>
        <li><a href="#21-声明还是表达式">2.1 声明还是表达式</a></li>
        <li><a href="#22-函数就是值">2.2 函数就是值</a></li>
        <li><a href="#23-参数">2.3 参数</a></li>
        <li><a href="#24-重载">2.4 重载</a></li>
        <li><a href="#25-对象方法">2.5 对象方法</a></li>
        <li><a href="#26-总结">2.6 总结</a></li>
      </ul>
    </li>
    <li><a href="#理解对象">理解对象</a>
      <ul>
        <li><a href="#31-定义属性">3.1 定义属性</a></li>
        <li><a href="#32-属性探测">3.2 属性探测</a></li>
        <li><a href="#33-删除属性">3.3 删除属性</a></li>
        <li><a href="#34-属性枚举">3.4 属性枚举</a></li>
        <li><a href="#35-属性类型">3.5 属性类型</a></li>
        <li><a href="#36-属性特征">3.6 属性特征</a></li>
        <li><a href="#37-禁止修改对象">3.7 禁止修改对象</a></li>
        <li><a href="#38-总结">3.8 总结</a></li>
      </ul>
    </li>
    <li><a href="#4-构造函数和原型对象">4. 构造函数和原型对象</a>
      <ul>
        <li><a href="#41-构造函数">4.1 构造函数</a></li>
        <li><a href="#42-原型对象">4.2 原型对象</a></li>
        <li><a href="#总结">总结</a></li>
      </ul>
    </li>
    <li><a href="#5-继承">5. 继承</a>
      <ul>
        <li><a href="#51-原型对象链和-objectprototype">5.1 原型对象链和 Object.prototype</a></li>
        <li><a href="#52-继承">5.2 继承</a></li>
        <li><a href="#53-构造函数继承">5.3 构造函数继承</a></li>
        <li><a href="#54-构造函数窃取">5.4 构造函数窃取</a></li>
        <li><a href="#55-访问父类方法">5.5 访问父类方法</a></li>
      </ul>
    </li>
    <li><a href="#6-对象模式">6 对象模式</a>
      <ul>
        <li></li>
        <li><a href="#62-混入">6.2 混入</a></li>
        <li><a href="#63-作用域安全的构造函数">6.3 作用域安全的构造函数</a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <h1 id="javascriptes5的面向对象精要">JavaScript（ES5）的面向对象精要</h1>
<hr>
<h2 id="1原始类型和引用类型">1.原始类型和引用类型</h2>
<h3 id="11-什么是类型">1.1 什么是类型</h3>
<p><strong>原始类型</strong> 保存为简单数据值。
<strong>引用类型</strong> 保存为对象，其本质是指向内存位置的引用。</p>
<p>为了让开发者能够把原始类型和引用类型按相同的方式处理，JavaScript花费了很大的努力来保证语言的一致性。</p>
<p>其他编程语言用栈存原始类型，用对存储引用类型。而JavaScript则完全不同：它使用一个变量对象追踪变量的生存期。原始值被直接保存在变量对象内，而引用值则作为一个指针保存在变量对象内，该指针指向实际对象在内存中的存储位置。</p>
<!-- raw HTML omitted -->
<h3 id="12-原始类型">1.2 原始类型</h3>
<p>原始类型代表照原样保存的一些简单数据。
JavaScript共有 <strong>5</strong> 种原始类型：</p>
<ul>
<li>boolean    布尔，值为 <code>true</code> or <code>false</code></li>
<li>number     数字，值为任何整型或浮点数值</li>
<li>string     字符串，值为由单引号或双引号括住的单个字符或连续字符</li>
<li>null       空类型，仅有一个值：null</li>
<li>undefined  未定义，只有一个值：undefined（undefined会被赋给一个还没有初始化的变量）</li>
</ul>
<p>JavaScript和许多其他语言一样，原始类型的变量直接保存原始值（而不是一个指向对象的指针）。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">color1</span> <span class="o">=</span> <span class="s2">&#34;red&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">color2</span> <span class="o">=</span> <span class="nx">color1</span><span class="p">;</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">color1</span><span class="p">);</span> <span class="c1">// &#34;red&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">color2</span><span class="p">);</span> <span class="c1">// &#34;red&#34;
</span><span class="c1"></span>    
    <span class="nx">color1</span> <span class="o">=</span> <span class="s2">&#34;blue&#34;</span><span class="p">;</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">color1</span><span class="p">);</span> <span class="c1">// &#34;blue&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">color2</span><span class="p">);</span> <span class="c1">// &#34;red&#34;
</span></code></pre></td></tr></table>
</div>
</div><h4 id="鉴别原始类型">鉴别原始类型</h4>
<p>鉴别原始类型的最佳方式是使用 <code>typeof</code> 操作符。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">);</span> <span class="c1">// &#34;string&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="mi">10</span><span class="p">);</span>         <span class="c1">// &#34;number&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// &#34;boolean&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="kc">undefined</span><span class="p">);</span>  <span class="c1">// &#34;undefined&#34;
</span><span class="c1"></span>    
</code></pre></td></tr></table>
</div>
</div><p>至于空类型（null）则有些棘手。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="kc">null</span><span class="p">);</span> <span class="c1">// &#34;object&#34;
</span><span class="c1"></span>

</code></pre></td></tr></table>
</div>
</div><p>对于 typeof null，结果是&quot;object&quot;。（其实这已被设计和维护JavaScript的委员会TC39认定是一个错误。在逻辑上，你可以认为 <code>null</code> 是一个空的对象指针，所以结果为&quot;object&quot;，但这还是很令人困惑。）</p>
<p>判断一个值是否为空类型（null）的最佳方式是直接和 <code>null</code> 比较：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">value</span> <span class="o">===</span> <span class="kc">null</span><span class="p">);</span> <span class="c1">// true or false
</span><span class="c1"></span>

</code></pre></td></tr></table>
</div>
</div><blockquote>
<p><strong>注意：以上这段代码使用了三等号（全等===）</strong>，因为三等号（全等）不会将变量强制转换为另一种类型。</p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;5&#34;</span> <span class="o">==</span> <span class="mi">5</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;5&#34;</span> <span class="o">===</span> <span class="mi">5</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="kc">undefined</span> <span class="o">==</span> <span class="kc">null</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="kc">undefined</span> <span class="o">===</span> <span class="kc">null</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h4 id="原始方法">原始方法</h4>
<p>虽然字符串、数字和布尔值是原始类型，但是它们也拥有方法（null和undefined没有方法）。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">lowercaseName</span> <span class="o">=</span> <span class="nx">name</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">();</span> <span class="c1">// 转为小写
</span><span class="c1"></span>    
    <span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">fixedCount</span> <span class="o">=</span> <span class="nx">count</span><span class="p">.</span><span class="nx">toFixed</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="c1">// 转为10.00
</span><span class="c1"></span>    
    <span class="kd">var</span> <span class="nx">flag</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">stringFlag</span> <span class="o">=</span> <span class="nx">flag</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span> <span class="c1">// 转为&#34;true&#34;
</span><span class="c1"></span>    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;YIBU&#34;</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span> <span class="c1">// 输出&#34;Y&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>尽管原始类型拥有方法，但它们不是对象。JavaScript使它们看上去像对象一样，以此来提高语言上的一致性体验。</p>
</blockquote>
<h3 id="13-引用类型">1.3 引用类型</h3>
<p>引用类型是指JavaScript中的对象，同时也是你在该语言中能找到最接近类的东西。
引用值是引用类型的实例，也是对象的同义词（后面将用对象指代引用值）。对象是属性的无序列表。属性包含键（始终是字符串）和值。如果一个属性的值是函数，它就被称为方法。除了函数可以运行以外，一个包含数组的属性和一个包含函数的属性没有什么区别。</p>
<h4 id="创建对象">创建对象</h4>
<p>有时候，把JavaScript对象想象成哈希表可以帮助你更好地理解对象结构。</p>
<p>![Object][1]</p>
<p>JavaScript 有好几种方法可以创建对象，或者说实例化对象。第一种是使用 <code>new</code> 操作符和构造函数。
构造函数就是通过 <code>new</code> 操作符来创建对象的函数——任何函数都可以是构造函数。根据命名规范，JavaScript中的构造函数用<strong>首字母大写</strong>来跟非构造函数进行区分。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">object</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>

</code></pre></td></tr></table>
</div>
</div><p>因为引用类型不再变量中直接保存对象，所以本例中的 <code>object</code> 变量实际上并<strong>不包含对象的实例，而是一个指向内存中实际对象所在位置的指针（或者说引用）</strong>。这是对象和原始值之间的一个基本差别，原始值是直接保存在变量中。</p>
<p>当你将一个对象赋值给变量时，实际是赋值给这个变量一个指针。这意味着，将一个变量赋值给另外一个变量时，两个变量各获得了一份指针的拷贝，指向内存中的同一个对象。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">obj2</span> <span class="o">=</span> <span class="nx">obj1</span><span class="p">;</span>

</code></pre></td></tr></table>
</div>
</div><p>![copy_obj][2]</p>
<h4 id="对象引用解除">对象引用解除</h4>
<p>JavaScript语言有垃圾收集的功能，因此当你使用引用类型时无需担心内存分配。<strong>但最好在不使用对象时将其引用解除，让垃圾收集器对那块内存进行释放。解除引用的最佳手段是将对象变量设置为 <code>null</code>。</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>
    <span class="c1">// dosomething
</span><span class="c1"></span>    <span class="nx">obj1</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span> <span class="c1">// dereference
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h4 id="添加删除属性">添加删除属性</h4>
<p>在JavaScript中，你可以随时添加和删除其属性。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">obj2</span> <span class="o">=</span> <span class="nx">obj1</span><span class="p">;</span>
    
    <span class="nx">obj1</span><span class="p">.</span><span class="nx">myCustomProperty</span> <span class="o">=</span> <span class="s2">&#34;Awsome!&#34;</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj2</span><span class="p">.</span><span class="nx">myCustomProperty</span><span class="p">);</span> <span class="c1">// &#34;Awsome!&#34; 因为obj1和obj2指向同一个对象。
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h3 id="14-内建类型实例化">1.4 内建类型实例化</h3>
<p>内建类型如下：</p>
<ul>
<li>Array       数组类型，以数字为索引的一组值的有序列表</li>
<li>Date        日期和时间类型</li>
<li>Error       运行期错误类型</li>
<li>Function    函数类型</li>
<li>Object      通用对象类型</li>
<li>RegExp      正则表达式类型</li>
</ul>
<p>可使用 <code>new</code> 来实例化每一个内建引用类型：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">items</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">();</span>
    <span class="kd">var</span> <span class="k">new</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">error</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&#34;Something bad happened.&#34;</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">func</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="s2">&#34;console.log(&#39;HI&#39;);&#34;</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">object</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">re</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">RegExp</span><span class="p">();</span>

</code></pre></td></tr></table>
</div>
</div><h4 id="字面形式">字面形式</h4>
<p>内建引用类型有字面形式。字面形式允许你在不需要使用 <code>new</code> 操作符和构造函数显示创建对象的情况下生成引用值。属性的<strong>键</strong>可以是标识符或字符串（若含有空格或其他特殊字符）</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">book</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Book_name&#34;</span><span class="p">,</span>
        <span class="nx">year</span><span class="o">:</span> <span class="mi">2016</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>上面代码与下面这段代码等价：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">book</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>
    <span class="nx">book</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Book_name&#34;</span><span class="p">;</span>
    <span class="nx">book</span><span class="p">.</span><span class="nx">year</span> <span class="o">=</span> <span class="mi">2016</span><span class="p">;</span>

</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>虽然使用字面形式并没有调用 new Object()，但是JavaScript引擎背后做的工作和 new Object()一样，除了没有调用构造函数。其他引用类型的字面形式也是如此。</p>
</blockquote>
<h3 id="15-访问属性">1.5 访问属性</h3>
<p>可通过 <code>.</code> 和 <code>中括号</code> 访问对象的属性。
中括号<code>[]</code>在需要动态决定访问哪个属性时，特别有用。因为你可以用<strong>变量</strong>而不是字符串字面形式来指定访问的属性。</p>
<h3 id="16-鉴别引用类型">1.6 鉴别引用类型</h3>
<p>函数是最容易鉴别的引用类型，因为对函数使用 <code>typeof</code> 操作符时，返回&quot;function&quot;。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">reflect</span><span class="p">(</span><span class="nx">value</span><span class="p">){</span>
        <span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">reflect</span><span class="p">);</span> <span class="c1">// &#34;function&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>对其他引用类型的鉴别则较为棘手，因为对于所有非函数的引用类型，<code>typeof</code> 返回 <code>object</code>。为了更方便地鉴别引用类型，可以使用 JavaScript 的 <code>instanceof</code> 操作符。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">items</span> <span class="o">=</span> <span class="p">[];</span>
    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
    <span class="kd">function</span> <span class="nx">reflect</span><span class="p">(</span><span class="nx">value</span><span class="p">){</span>
        <span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">items</span> <span class="k">instanceof</span> <span class="nb">Array</span><span class="p">);</span> <span class="c1">// true;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span> <span class="k">instanceof</span> <span class="nb">Object</span><span class="p">);</span> <span class="c1">// true;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">reflect</span> <span class="k">instanceof</span> <span class="nb">Function</span><span class="p">);</span> <span class="c1">// true;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p><code>instanceof</code> 操作符可鉴别继承类型。这意味着所有对象都是 <code>Oject</code> 的实例，因为所有引用类型都继承自 <code>Object</code>。</p>
<blockquote>
<p>虽然 instanceof 可以鉴别对象类型（如数组），但是有一个列外。JavaScript 的值可以在同一个网页的不用框架之间传来传去。由于每个网页拥有它自己的全局上下文——Object、Array以及其他内建类型的版本。所以当你把一个对象（如数组）从一个框架传到另外一个框架时，instanceof就无法识别它。</p>
</blockquote>
<h3 id="18-原始封装类型">1.8 原始封装类型</h3>
<p>原始封装类型有 <code>3</code> 种：String、Number 和 Boolean。
当读取字符串、数字或布尔值时，原始封装类型将被自动创建。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">firstChar</span> <span class="o">=</span> <span class="nx">name</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="c1">// &#34;N&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>这在背后发生的事情如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Nichola&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">temp</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">String</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">firstChar</span> <span class="o">=</span> <span class="nx">temp</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
    <span class="nx">temp</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>

</code></pre></td></tr></table>
</div>
</div><p>由于第二行把字符串当成对象使用，JavaScript引擎创建了一个字符串的实体让 <code>charAt(0)</code> 可以工作。字符串对象的存在仅用于该语句并在随后销毁（一种被称为自动打包的过程）。为了测试这一点，试着给字符串添加一个属性看看它是不是对象。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">;</span>
    <span class="nx">name</span><span class="p">.</span><span class="nx">last</span> <span class="o">=</span> <span class="s2">&#34;Zakas&#34;</span><span class="p">;</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">name</span><span class="p">.</span><span class="nx">last</span><span class="p">);</span> <span class="c1">// undefined;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>下面是在JavaScript引擎中实际发生的事情：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">temp</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">String</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
    <span class="nx">temp</span><span class="p">.</span><span class="nx">last</span> <span class="o">=</span> <span class="s2">&#34;Zakas&#34;</span><span class="p">;</span>
    <span class="nx">temp</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span> <span class="c1">// temporary object destroyed
</span><span class="c1"></span>    
    <span class="kd">var</span> <span class="nx">temp</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">String</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">temp</span><span class="p">.</span><span class="nx">last</span><span class="p">);</span>
    <span class="nx">temp</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>

</code></pre></td></tr></table>
</div>
</div><p>新属性 <code>last</code> 实际上是在一个立刻就被销毁的临时对象上而不是字符串上添加。之后当你试图访问该属性时，另一个不同的临时对象被创建，而新属性并不存在。</p>
<p>虽然原始封装类型会被自动创建，在这些值上进行 <code>instanceof</code> 检查对应类型的返回值却是 <code>false</code>。
这是因为<strong>临时对象仅在值被读取时创建</strong>。<code>instanceof</code> 操作符并没有真的读取任何东西，也就没有临时对象的创建。</p>
<p>当然你也可以手动创建原始封装类型。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">str</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">String</span><span class="p">(</span><span class="s2">&#34;me&#34;</span><span class="p">);</span>
    <span class="nx">str</span><span class="p">.</span><span class="nx">age</span> <span class="o">=</span> <span class="mi">18</span><span class="p">;</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">str</span><span class="p">);</span> <span class="c1">// object
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">str</span><span class="p">.</span><span class="nx">age</span><span class="p">);</span> <span class="c1">// 18
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>如你所见，手动创建原始封装类型实际会创建出一个 <code>object</code>。这意味着 <code>typeof</code> 无法鉴别出你实际保存的数据的类型。</p>
<p>另外，手动创建原始封装类型和使用原始值是有一定区别的。所以尽量避免使用。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">found</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Boolean</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">found</span><span class="p">){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Found&#34;</span><span class="p">);</span> <span class="c1">// 执行到了，尽管对象的值为 false
</span><span class="c1"></span>    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>这是因为一个对象(如 <code>{}</code> )在条件判断语句中总被认为是 <code>true</code>;</p>
<blockquote>
<p>MDN:Any object whose value is not undefined or null, including a Boolean oject whose value is false, evaluates to true when passed to a conditional statement.</p>
</blockquote>
<h3 id="19-总结">1.9 总结</h3>
<p>第一章的东西都是我们一些比较熟悉的知识。但是也有一些需要注意的地方：</p>
<ul>
<li>正确区分原始类型和引用类型</li>
<li>对于 <code>5</code> 种原始类型都可以用typeof来鉴别，而空类型必须直接跟 <code>null</code> 进行全等比较。</li>
<li>函数也是对象，可用 <code>typeof</code> 鉴别。其它引用类型，可用 <code>instanceof</code> 和一个构造函数来鉴别。（当然可以用  <code>Object.prototype.toString.call()</code> 鉴别，它会返回[object Array]之类的）。</li>
<li>为了让原始类型看上去更像引用类型，JavaScript提供了 <code>3</code> 种封装类型。JavaScript会在背后创建这些对象使得你能够像使用普通对象那样使用原始值。但这些临时对象在使用它们的语句结束时就立刻被销毁。虽然可手动创建，但不建议。</li>
</ul>
<h2 id="2-函数">2. 函数</h2>
<p>函数也是对象，使对象不同于其它对象的决定性特点是函数存在一个被称为 <code>[[Call]]</code> 的内部属性。
<strong>内部属性无法通过代码访问而是定义了代码执行时的行为</strong>。ECMAScript为JavaScript的对象定义了多种内部属性，这些<strong>内部属性都用双重中括号来标注</strong>。</p>
<p><strong>[[Call]]属性是函数独有的，表明该对象可以被执行。由于仅函数拥有该属性，ECMAScript 定义typeof操作符对任何具有[[Call]]属性的对象返回&quot;function&quot;</strong>。过去因某些浏览器曾在正则表达式中包含 <code>[[Call]]</code> 属性，导致正则表达式被错误鉴别为函数。</p>
<h3 id="21-声明还是表达式">2.1 声明还是表达式</h3>
<p>两者的一个重要区别是：函数声明会被提升至上下文（要么是该函数被声明时所在的函数范围，要么是全局范围）的顶部。</p>
<h3 id="22-函数就是值">2.2 函数就是值</h3>
<p>可以像使用对象一样使用函数（因为函数本来就是对象，Function构造函数更加容易说明）。</p>
<h3 id="23-参数">2.3 参数</h3>
<p>函数参数保存在类数组对象 <code>argument</code> （<code>Array.isArray(arguments)</code> 返回 <code>false</code>）中。可以接收任意数量的参数。
函数的 <code>length</code> 属性表明其期望的参数个数。</p>
<h3 id="24-重载">2.4 重载</h3>
<p>大多数面向对象语言支持函数重载，它能让一个函数具有多个签名。函数签名由函数的名字、参数的个数及其类型组成。
而JavaScript可以接收任意数量的参数且参数类型完全没有限制。这说明JavaScript函数根本就没有签名，因此也不存在重载。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">sayMessage</span><span class="p">(</span><span class="nx">message</span><span class="p">){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">message</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="kd">function</span> <span class="nx">sayMessage</span><span class="p">(){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Default Message&#34;</span><span class="p">);</span>
    <span class="p">}</span>
    
    <span class="nx">sayMessage</span><span class="p">(</span><span class="s2">&#34;Hello!&#34;</span><span class="p">);</span> <span class="c1">// 输出&#34;Default Message&#34;;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>在Javscript里，当你试图定义多个同名的函数时，只有最后的定义有效，之前的函数声明被完全删除（函数也是对象，变量只是存指针)。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">sayMessage</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">,</span> <span class="s2">&#34;console.log(message)&#34;</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">sayMessage</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="s2">&#34;console.log(\&#34;Default Message\&#34;);&#34;</span><span class="p">);</span>
    
    <span class="nx">sayMessage</span><span class="p">(</span><span class="s2">&#34;Hello!&#34;</span><span class="p">);</span> 

</code></pre></td></tr></table>
</div>
</div><p>当然，你可以根据传入参数的数量来模仿重载。</p>
<h3 id="25-对象方法">2.5 对象方法</h3>
<p>对象的值是函数，则该属性被称为方法。</p>
<h4 id="251-this对象">2.5.1 this对象</h4>
<p>JavaScript 所有的函数作用域内都有一个 <code>this</code> 对象代表调用该函数的对象。在全局作用域中，<code>this</code> 代表全局对象（浏览器里的window）。当一个函数作为对象的方法调用时，默认 <code>this</code> 的值等于该对象。
<strong>this在函数调用时才被设置。</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">sayNameForAll</span><span class="p">(){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
    <span class="p">}</span>
    
    <span class="kd">var</span> <span class="nx">person1</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">,</span>
        <span class="nx">sayName</span><span class="o">:</span> <span class="nx">sayNameForAll</span>
    <span class="p">}</span>
    
    <span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Jack&#34;</span><span class="p">;</span>
    
    <span class="nx">person1</span><span class="p">.</span><span class="nx">sayName</span><span class="p">();</span> <span class="c1">// 输出 &#34;Nicholas&#34;
</span><span class="c1"></span>    <span class="nx">sayNameforAll</span><span class="p">();</span> <span class="c1">// 输出 &#34;Jack&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h4 id="252-改变this">2.5.2 改变this</h4>
<p>有 <code>3</code> 种函数方法运行你改变 <code>this</code> 值。</p>
<ol>
<li>fun.call(thisArg[, arg1[, arg2[, &hellip;]]]);</li>
<li>fun.apply(thisArg, [argsArray]);</li>
<li>fun.bind(thisArg[, arg1[, arg2[, &hellip;]]])</li>
</ol>
<p>使用 <code>call</code> 或 <code>apply</code> 方法，就不需要将函数加入每个对象——你显示地指定了 <code>this</code> 的值而不是让JavaScript引擎自动指定。</p>
<p><code>call</code> 与 <code>apply</code> 的不同地方是，<code>call</code> 需要把所有参数一个个列出来，而 <code>apply</code> 的参数需要一个数组或者类似数组的对象（如 <code>arguments</code> 对象）。</p>
<p><code>bind</code> 是ECMAScript 5 新增的，它会创建一个新函数返回。其参数与 <code>call</code> 类似，而且其所有参数代表需要被<strong>永久</strong>设置在新函数中的命名参数（绑定了的参数（没绑定的参数依然可以传入），就算调用时再传入其它参数，也不会影响这些绑定的参数）。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">sayNameForAll</span><span class="p">(</span><span class="nx">label</span><span class="p">){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">label</span> <span class="o">+</span> <span class="s2">&#34;:&#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span>
    <span class="p">}</span>
    
    <span class="kd">var</span> <span class="nx">sayNameForPerson</span> <span class="o">=</span> <span class="nx">sayNameForAll</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">person</span><span class="p">);</span>
    <span class="nx">sayNameForPerson</span><span class="p">(</span><span class="s2">&#34;Person&#34;</span><span class="p">);</span> <span class="c1">// 输出&#34;Person:Nicholas&#34;
</span><span class="c1"></span>    
    <span class="kd">var</span> <span class="nx">sayName</span> <span class="o">=</span> <span class="nx">sayNameForAll</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;Jc&#34;</span><span class="p">);</span>
    
    <span class="nx">sayName</span><span class="p">(</span><span class="s2">&#34;change&#34;</span><span class="p">);</span> <span class="c1">// 输出&#34;Jc:Nicholas&#34; 因为绑定的形参，会忽略调用时再传入参数
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h3 id="26-总结">2.6 总结</h3>
<ul>
<li>函数也是对象，所以它可以被访问、复制和覆盖。</li>
<li>函数与其他对象最大的区别在于它们有一个特殊的内部属性 <code>[[Call]]</code>，包含了该函数的执行指令。</li>
<li>函数声明会被提升至上下文的顶部。</li>
<li>函数是对象，所以存在一个 <code>Function</code> 构造函数。但这会使你的代码难以理解和调试，除非函数的真实形式要直到运行时才能确定的时候才会利用它。</li>
</ul>
<h2 id="理解对象">理解对象</h2>
<p>JavaScript中的对象是动态的，可在代码执行的任意时刻发生改变。基于类的语言会根据类的定义锁定对象。</p>
<h3 id="31-定义属性">3.1 定义属性</h3>
<p>当一个属性第一次被添加到对象时，JavaScript会在对象上调用一个名为 <code>[[Put]]</code> 的内部方法。<code>[[Put]]</code> 方法会在对象上创建一个新节点来保存属性。
当一个已有的属性被赋予一个新值时，调用的是一个名为 <code>[[Set]]</code> 的方法。</p>
<h3 id="32-属性探测">3.2 属性探测</h3>
<p>检查对象是否已有一个属性。JavaScript开发新手错误地使用以下模式检测属性是否存在。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="k">if</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">age</span><span class="p">){</span>
        <span class="c1">// do something with ag
</span><span class="c1"></span>    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>上面的问题在于JavaScript的类型强制会影响该模式的输出结果。
当if判断中的值如下时，会判断为<strong>真</strong>：</p>
<ul>
<li>对象</li>
<li>非空字符串</li>
<li>非零</li>
<li>true</li>
</ul>
<p>当if判断中的值如下时，会判断为<strong>假</strong>：</p>
<ul>
<li>null</li>
<li>undefined</li>
<li>0</li>
<li>false</li>
<li>NaN</li>
<li>空字符串</li>
</ul>
<p>因此判断属性是否存在的方法是使用 <code>in</code> 操作符。
<code>in</code> 操作符会检查<strong>自有属性和原型属性</strong>。
所有的对象都拥有的 <code>hasOwnProperty()</code> 方法（其实是 <code>Object.prototype</code> 原型对象的），该方法在给定的属性存在且为<strong>自有属性</strong>时返回 <code>true</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span>
    <span class="p">}</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;name&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">hasOwnpropert</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">));</span> <span class="c1">// true
</span><span class="c1"></span>    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;toString&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">hasOwnproperty</span><span class="p">(</span><span class="s2">&#34;toString&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h3 id="33-删除属性">3.3 删除属性</h3>
<p>设置一个属性的值为 <code>null</code> 并不能从对象中彻底移除那个属性，这只是调用 <code>[[Set]]</code> 将 <code>null</code> 值替换了该属性原来的值而已。
<code>delete</code> 操作符针对单个对象属性调用名为 <code>[[Delete]]</code> 的内部方法。删除成功时，返回 <code>true</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span>
    <span class="p">}</span>
    
    <span class="nx">person</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;name&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="k">delete</span> <span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// undefined 访问一个不存在的属性将返回 undefined
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;name&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h3 id="34-属性枚举">3.4 属性枚举</h3>
<p>所有人为添加的属性默认都是可枚举的。可枚举的内部特征 <code>[[Enumerable]]</code> 都被设置为 <code>true</code>。
<code>for-in</code> 循环会枚举一个对象所有的可枚举属性。</p>
<blockquote>
<p>我的备注：在Chrome中，对象属性会按ASCII表排序，而不是定义时的顺序。</p>
</blockquote>
<p>ECMAScript 5 的 Object() 方法可以获取可枚举属性的名字的数组。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Ljc&#34;</span><span class="p">,</span>
        <span class="nx">age</span><span class="o">:</span> <span class="mi">18</span>
    <span class="p">}</span>
    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">person</span><span class="p">);</span> <span class="c1">// [&#34;name&#34;, &#34;age&#34;];
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p><code>for-in</code> 与 <code>Object.keys()</code> 的一个区别是：前者也会遍历原型属性，而后者返回自有(实例)属性。</p>
<p>实际上，对象的大部分原生方法的 <code>[[Enumerable]]</code> 特征都被设置为 <code>false</code>。可用 <code>propertyIsEnumerable()</code> 方法检查一个属性是否为可枚举的。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">arr</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;abc&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">];</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">arr</span><span class="p">.</span><span class="nx">propertyIsEnumerable</span><span class="p">(</span><span class="s2">&#34;length&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>

</code></pre></td></tr></table>
</div>
</div><h3 id="35-属性类型">3.5 属性类型</h3>
<p>属性有两种类型：<strong>数据属性</strong>和<strong>访问器属性</strong>。
数据属性包含一个值。<code>[[Put]]</code> 方法的默认行为是创建<strong>数据属性</strong>。
访问器属性不包含值而是定义了一个当属性被读取时调用的函数（称为<code>getter</code>）和一个当属性被写入时调用的函数（称为<code>setter</code>）。访问器属性仅需要 <code>getter</code> 或 <code>setter</code> 两者中的任意一个，当然也可以两者。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="c1">// 对象字面形式中定义访问器属性有特殊的语法：
</span><span class="c1"></span>    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">_name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">,</span>
        
        <span class="nx">get</span> <span class="nx">name</span><span class="p">(){</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Reading name&#34;</span><span class="p">);</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_name</span><span class="p">;</span>
        <span class="p">},</span>
        <span class="nx">set</span> <span class="nx">name</span><span class="p">(</span><span class="nx">value</span><span class="p">){</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Setting name to %s&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">_name</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">};</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// &#34;Reading name&#34; 然后输出 &#34;Nicholas&#34;
</span><span class="c1"></span>    
    <span class="nx">person</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="s2">&#34;Greg&#34;</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// &#34;Setting name to Greg&#34; 然后输出 &#34;Greg&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>前置下划线_ 是一个约定俗成的命名规范，表示该属性是私有的，实际上它还是公开的。</p>
</blockquote>
<p>访问器就是定义了我们在对象读取或设置属性时，触发的动作（函数），<code>_name</code> 相当于一个内部变量。
当你希望赋值（读取）操作会触发一些行为，访问器就会非常有用。</p>
<blockquote>
<p>当只定义getter或setter其一时，该属性就会变成只读或只写。</p>
</blockquote>
<h3 id="36-属性特征">3.6 属性特征</h3>
<p>在ECMAScript 5 之前没有办法指定一个属性是否可枚举。实际上根本没有方法访问属性的任何内部特征。为了改变这点，ECMAScript 5引入了多种方法来和属性特征值直接互动。</p>
<h4 id="361-通用特征">3.6.1 通用特征</h4>
<p>数据属性和访问器属性均由以下两个属性特制：
<code>[[Enumerable]]</code> 决定了是否可以遍历该属性；
<code>[[Configurable]]</code> 决定了该属性是否可配置。</p>
<p>所有人为定义的属性默认都是可枚举、可配置的。</p>
<p>可以用 <code>Object.defineProperty()</code> 方法改变属性特征。
其参数有三：拥有该属性的对象、属性名和包含需要设置的特性的属性描述对象。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span>
    <span class="p">}</span>
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">false</span>
    <span class="p">})</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;name&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">propertyIsEnumerable</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>    
    <span class="kd">var</span> <span class="nx">properties</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">person</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">properties</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span> <span class="c1">// 0
</span><span class="c1"></span>    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">,{</span>
        <span class="nx">configurable</span><span class="o">:</span> <span class="kc">false</span>
    <span class="p">})</span>
    
    <span class="k">delete</span> <span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;name&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">,{</span> <span class="c1">// error! 
</span><span class="c1"></span>    <span class="c1">// 在 chrome：Uncaught TypeError: Cannot redefine property: name
</span><span class="c1"></span>        <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span>
    <span class="p">})</span>

</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>无法将一个不可配置的属性变为可配置，相反则可以。</p>
</blockquote>
<h4 id="362-数据属性特征">3.6.2 数据属性特征</h4>
<p>数据属性额外拥有两个访问器属性不具备的特征。
<code>[[Value]]</code> 包含属性的值(哪怕是函数)。
<code>[[Writable]]</code> 布尔值，指示该属性是否可写入。所有属性默认都是可写的。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{};</span>
    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">,</span>
        <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
        <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
        <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span>
    <span class="p">})</span>

</code></pre></td></tr></table>
</div>
</div><p><strong>如果原型对象的某个属性的writable为false，那么子对象将无法自定义这个属性。</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="kd">var</span> <span class="nx">proto</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">({},</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="p">{</span>
  <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span>
  <span class="nx">writable</span><span class="o">:</span> <span class="kc">false</span>
<span class="p">});</span>

<span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">proto</span><span class="p">);</span>

<span class="nx">obj</span><span class="p">.</span><span class="nx">foo</span> <span class="o">=</span> <span class="s1">&#39;b&#39;</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">foo</span> <span class="c1">// &#39;a&#39;
</span></code></pre></td></tr></table>
</div>
</div><p>上面代码中，proto是原型对象，它的foo属性不可写。obj对象继承proto，也不可以再自定义这个属性了。如果是严格模式，这样做还会抛出一个错误。</p>
<p>但是，有一个规避方法，就是通过覆盖属性描述对象，绕过这个限制。原因是这种情况下，原型链会被完全忽视。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="kd">var</span> <span class="nx">proto</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">({},</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="p">{</span>
  <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span>
  <span class="nx">writable</span><span class="o">:</span> <span class="kc">false</span>
<span class="p">});</span>

<span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">proto</span><span class="p">);</span>
<span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="p">{</span>
  <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;b&#39;</span>
<span class="p">});</span>

<span class="nx">obj</span><span class="p">.</span><span class="nx">foo</span> <span class="c1">// &#34;b&#34;
</span></code></pre></td></tr></table>
</div>
</div><p><strong>至于value，只要writable和configurable有一个为true，就允许改动。</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="kd">var</span> <span class="nx">o1</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">({},</span> <span class="s1">&#39;p&#39;</span><span class="p">,</span> <span class="p">{</span>
  <span class="nx">value</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span>
  <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
  <span class="nx">configurable</span><span class="o">:</span> <span class="kc">false</span>
<span class="p">});</span>

<span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">o1</span><span class="p">,</span> <span class="s1">&#39;p&#39;</span><span class="p">,</span> <span class="p">{</span><span class="nx">value</span><span class="o">:</span> <span class="mi">2</span><span class="p">})</span>
<span class="c1">// 修改成功
</span><span class="c1"></span>
<span class="kd">var</span> <span class="nx">o2</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">({},</span> <span class="s1">&#39;p&#39;</span><span class="p">,</span> <span class="p">{</span>
  <span class="nx">value</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span>
  <span class="nx">writable</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
  <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span>
<span class="p">});</span>

<span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">o2</span><span class="p">,</span> <span class="s1">&#39;p&#39;</span><span class="p">,</span> <span class="p">{</span><span class="nx">value</span><span class="o">:</span> <span class="mi">2</span><span class="p">})</span>
<span class="c1">// 修改成功
</span></code></pre></td></tr></table>
</div>
</div><p>在 <code>Object.defineProperty()</code> 被调用时，如果属性本来就有，则会按照新定义属性特征值去覆盖默认属性特征（<code>enumberable</code>、<code>configurable</code> 和 <code>writable</code> 均为 <code>true</code>）。但如果用该方法定义新的属性时，没有为所有的特征值指定一个值，则所有布尔值的特征值会被默认设置为 <code>false</code>。即不可枚举、不可配置、不可写的。
当你用 <code>Object.defineProperty()</code> 改变一个已有的属性时，只有你指定的特征会被改变。</p>
<h4 id="363-访问器属性特征">3.6.3 访问器属性特征</h4>
<p>访问器属性额外拥有两个特征。<code>[[Get]]</code> 和 <code>[[Set]]</code>，内含 <code>getter</code> 和 <code>setter</code> 函数。
使用访问其属性特征比使用对象字面形式定义访问器属性的优势在于：可以为已有的对象定义这些属性。而后者只能在创建时定义访问器属性。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">_name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span>
    <span class="p">};</span>
    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">get</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_name</span><span class="p">;</span>
        <span class="p">},</span>
        <span class="nx">set</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">value</span><span class="p">){</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">_name</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
        <span class="p">},</span>
        <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
        <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span>
    <span class="p">})</span>
    
    <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">x</span> <span class="k">in</span> <span class="nx">person</span><span class="p">){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">x</span><span class="p">);</span> <span class="c1">// _name \n(换行) name（访问器属性）
</span><span class="c1"></span>    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>取值函数get不能接受参数，存值函数set只能接受一个参数（即属性的值）</p>
<p>设置一个不可配置、不可枚举、不可以写的属性：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">,{</span>
        <span class="nx">get</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_name</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">})</span>

</code></pre></td></tr></table>
</div>
</div><p>对于一个新的访问器属性，没有显示设置值为布尔值的属性，默认为 <code>false</code>。</p>
<h4 id="364-定义多重属性">3.6.4 定义多重属性</h4>
<p><code>Object.defineProperties()</code> 方法可以定义任意数量的属性，甚至可以同时改变已有的属性并创建新属性。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{};</span>
    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperties</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="p">{</span>
        
        <span class="c1">// data property to store data
</span><span class="c1"></span>        <span class="nx">_name</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">,</span>
            <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span>
        <span class="p">},</span>
        
        <span class="c1">// accessor property
</span><span class="c1"></span>        <span class="nx">name</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">get</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
                <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_name</span><span class="p">;</span>
            <span class="p">},</span>
            <span class="nx">set</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">value</span><span class="p">){</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">_name</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">})</span>

</code></pre></td></tr></table>
</div>
</div><h4 id="365-获取属性特征">3.6.5 获取属性特征</h4>
<p><code>Object.getOwnPropertyDescriptor()</code> 方法。该方法接受两个参数：对象和属性名。如果属性存在，它会返回一个属性描述对象，内涵<code>4</code>个属性：<code>configurable</code> 和 <code>enumerable</code>，另外两个属性则根据属性类型决定。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span>
    <span class="p">}</span>
    
    <span class="kd">var</span> <span class="nx">descriptor</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyDescriptor</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">);</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">descriptor</span><span class="p">.</span><span class="nx">enumerable</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">descriptor</span><span class="p">.</span><span class="nx">configuable</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">descriptor</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span> <span class="c1">// &#34;Nicholas&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">descriptor</span><span class="p">.</span><span class="nx">wirtable</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h3 id="37-禁止修改对象">3.7 禁止修改对象</h3>
<p>对象和属性一样具有指导其行为的内部特性。其中， <code>[[Extensible]]</code> 是布尔值，指明该对象本身是否可以被修改。默认是 <code>true</code>。当值为 <code>false</code> 时，就能禁止新属性的添加。</p>
<blockquote>
<p>建议在 &ldquo;use strict&rdquo;; 严格模式下进行。</p>
</blockquote>
<h4 id="371-禁止扩展">3.7.1 禁止扩展</h4>
<p><code>Object.preventExtensions()</code> 创建一个不可扩展的对象（即<strong>不能添加新属性</strong>）。
<code>Object.isExtensible()</code> 检查 <code>[[Extensible]]</code> 的值。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nocholas&#34;</span>
    <span class="p">}</span>
    
    <span class="nb">Object</span><span class="p">.</span><span class="nx">preventExtensions</span><span class="p">(</span><span class="nx">person</span><span class="p">);</span>
    
    <span class="nx">person</span><span class="p">.</span><span class="nx">sayName</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;sayName&#34;</span> <span class="k">in</span> <span class="nx">person</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h4 id="372-对象封印">3.7.2 对象封印</h4>
<p>一个被封印的对象是不可扩展的且其所有属性都是不可配置的（即不能添加、删除属性或修改其属性类型（从数据属性变成访问器属性或相反））。<strong>只能读写它的属性</strong>。
Object.seal()。调用此方法后，该对象的 <code>[[Extensible]]</code> 特征被设置为 <code>false</code>，其所有属性的 <code>[[configurable]]</code> 特征被设置为 <code>false</code>。
<code>Object.isSealed()</code> 判断一个对象是否被封印。</p>
<h4 id="373-对象冻结">3.7.3 对象冻结</h4>
<p>被冻结的对象不能添加或删除属性，不能修改属性类型，也不能写入任何数据属性。简言而之，被冻结对象是一个<strong>数据属性都为只读</strong>的被封印对象。
<code>Object.freeze()</code> 冻结对象。
<code>Object.isFrozen()</code> 判断对象是否被冻结。</p>
<h3 id="38-总结">3.8 总结</h3>
<ul>
<li><code>in</code> 操作符检测自有属性和原型属性，而 <code>hasOwnProperty()</code> 只检查自有属性。</li>
<li>用 <code>delete</code> 操作符删除对象属性。</li>
<li>属性有两种类型：数据属性和访问器属性。</li>
<li>所有属性都有一些相关特征。<code>[[Enumerable]]</code> 和 <code>[[Configurable]]</code> 的两种属性都有的，而数据属性还有 <code>[[Value]]</code> 和 <code>[[Writable]]</code>，访问器属性还有 <code>[[Get]]</code> 和 <code>[[Set]]</code>。可通过 <code>Object.defineProperty()</code> 和 <code>Object.defineProperties()</code> 改变这些特征。用 <code>Object.getOwnPropertyDescriptor()</code> 获取它们。</li>
<li>有 <code>3</code> 种可以锁定对象属性的方式。</li>
</ul>
<h2 id="4-构造函数和原型对象">4. 构造函数和原型对象</h2>
<p>由于JavaScript(ES5)缺乏类，但可用构造函数和原型对象给对象带来与类相似的功能。</p>
<h3 id="41-构造函数">4.1 构造函数</h3>
<p>构造函数的函数名首字母应大写，以此区分其他函数。
当没有需要给构造函数传递参数，可忽略小括号：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">Person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="c1">// 故意留空
</span><span class="c1"></span>    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">;</span>

</code></pre></td></tr></table>
</div>
</div><p>尽管 Person 构造函数没有显式返回任何东西，但 new 操作符会自动创建给定类型的对象并返回它们。</p>
<p>每个对象在创建时都自动拥有一个构造函数属性（constructor，其实是它们的原型对象上的属性），其中包含了一个指向其构造函数的引用。
通过对象字面量形式（{}）或Object构造函数创建出来的泛用对象，其构造函数属性（constructor）指向 Object；而那些通过自定义构造函数创建出来的对象，其构造函数属性指向创建它的构造函数。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">constructor</span> <span class="o">===</span> <span class="nx">Person</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(({}).</span><span class="nx">constructor</span> <span class="o">===</span> <span class="nb">Object</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(([</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]).</span><span class="nx">constructor</span> <span class="o">===</span> <span class="nb">Object</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    
    <span class="c1">// 证明 constructor是在原型对象上
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">hasOwnPrototype</span><span class="p">(</span><span class="s2">&#34;constructor&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">constructor</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">hasOwnPrototype</span><span class="p">(</span><span class="s2">&#34;constructor&#34;</span><span class="p">));</span> <span class="c1">// true
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>尽管对象实例及其构造函数之间存在这样的关系，但还是建议使用 <code>instanceof</code> 来检查对象类型。这是因为构造函数属性可以被覆盖。（person.constructor = &ldquo;&quot;）。</p>
<p>当你调用构造函数时，new 会自动自动创建 this 对象，且其类型就是构造函数的类型（构造函数就好像类，相当于一种数据类型）。</p>
<blockquote>
<p>你也可以在构造函数中显式调用 return。如果返回值是一个对象，它会代替新创建的对象实例而返回，如果返回值是一个原始类型，它会被忽略，新创建的对象实例会被返回。</p>
</blockquote>
<p>始终确保要用 new 调用构造函数；否则，你就是在冒着改变全局对象的风险，而不是创建一个新的对象。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;Nicholas&#34;</span><span class="p">);</span> <span class="c1">// 缺少 new
</span><span class="c1"></span>    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span> <span class="k">instanceof</span> <span class="nx">Person</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">);</span> <span class="c1">// undefined，因为没用 new，就相当于一个普通函数，默认返回 undefined
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// &#34;Nicholas&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>当Person不是被 new 调用时，构造函数中的 this 对象等于全局 this 对象。</p>
<blockquote>
<p>在严格模式下，会报错。因为严格模式下，并没有为全局对象设置 this，this 保持为 undefined。</p>
</blockquote>
<p>以下代码，通过 new 实例化 100 个对象，则会有 100 个函数做相同的事。因此可用 <code>prototype</code> 共享同一个方法会更高效。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Nicholas&#34;</span><span class="p">,</span>
        <span class="nx">sayName</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><h3 id="42-原型对象">4.2 原型对象</h3>
<p>可以把原型对象看作是对象的基类。几乎所有的函数（除了一些内建函数）都有一个名为 prototype 的属性，该属性是一个原型对象用来创建新的对象实例。所有创建的对象实例（同一构造函数，当然，可能访问上层的原型对象）<strong>共享</strong>该原型对象，且这些对象实例可以访问原型对象的属性。例如，hasOwnProperty()定义在 Object 的原型对象中，但却可被任何对象当作自己的属性访问。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">book</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">title</span> <span class="o">:</span> <span class="s2">&#34;book_name&#34;</span>
    <span class="p">}</span>
    
    <span class="s2">&#34;hasOwnProperty&#34;</span> <span class="k">in</span> <span class="nx">book</span><span class="p">;</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">book</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;hasOwnProperty&#34;</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nb">Object</span><span class="p">.</span><span class="nx">property</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;hasOwnProperty&#34;</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p><strong>鉴别一个原型属性</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">hasPrototypeProperty</span><span class="p">(</span><span class="nx">object</span><span class="p">,</span> <span class="nx">name</span><span class="p">){</span>
        <span class="k">return</span> <span class="nx">name</span> <span class="k">in</span> <span class="nx">object</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">object</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><h4 id="421-prototype-属性">4.2.1 [[Prototype]] 属性</h4>
<p>一个对象实例通过内部属性 [[Prototype]] 跟踪其原型对象。该属性是一个指向该实例使用的原型对象的指针。当你用 new 创建一个新的对象时，构造函数的原型对象就会被赋给该对象的 [[Prototype]] 属性。</p>
<p>![prototype][3]</p>
<p>由上图可以看出，[[Prototype]] 属性是如何让多个对象实例引用同一个原型对象来减少重复代码。</p>
<p>Object.getPrototypeOf() 方法可读取 [[Prototype]] 属性的值。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
    <span class="kd">var</span> <span class="nx">prototype</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getPrototypeOf</span><span class="p">(</span><span class="nb">Object</span><span class="p">);</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">prototype</span> <span class="o">===</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>大部分JavaScript引擎在所有对象上都支持一个名为 <code>__proto__</code> 的属性。该属性使你可以直接读写 [[Prototype]] 属性。</p>
</blockquote>
<p>isPrototypeOf() 方法会检查某个对象是否是另一个对象的原型对象，该方法包含在所有对象中。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">isPrototypeOf</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span> <span class="c1">// true
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>当读取一个对象的属性时，JavaScript 引擎首先在该对象的自有属性查找属性名。如果找到则返回。否则会搜索 [[Prototype]] 中的对象，找到则返回，找不到则返回 undefined。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">();</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="c1">// &#34;[object Object]&#34;
</span><span class="c1"></span>    
    <span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="k">return</span> <span class="s2">&#34;[object Custom]&#34;</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="c1">// &#34;[object Custom]&#34;
</span><span class="c1"></span>    
    <span class="k">delete</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span><span class="p">;</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="c1">// &#34;[object Object]&#34;
</span><span class="c1"></span>    
    <span class="k">delete</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span><span class="p">;</span> <span class="c1">// 无效，delete不能删除一个对象从原型继承而来的属性
</span><span class="c1"></span>    <span class="nx">cconsole</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="c1">// // &#34;[object Object]&#34;
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>MDN：delete 操作符不能删除的属性有：①显式声明的全局变量不能被删除,该属性不可配置（not configurable）； ②内置对象的内置属性不能被删除； ③不能删除一个对象从原型继承而来的属性(不过你可以从原型上直接删掉它)。</p>
</blockquote>
<p>一个重要概念：无法给一个对象的原型属性赋值。但我们可以通过 <code>obj.constructor.prototype.sayHi = function(){console.log(&quot;Hi!&quot;)}</code> 向原型对象添加属性。</p>
<p>![此处输入图片的描述][4]
（图片中间可以看出，为对象obj添加的toString属性代替了原型属性）</p>
<h4 id="422-在构造函数中使用原型对象">4.2.2 在构造函数中使用原型对象</h4>
<h5 id="在原型对象上定义公用方法">在原型对象上定义公用方法</h5>
<h5 id="在原型对象上定义数据类型">在原型对象上定义数据类型</h5>
<p>开发中需要注意原型对象的数据是否共享。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span>
    <span class="p">}</span>

    <span class="nx">Person</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">sayName</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nx">Person</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">position</span> <span class="o">=</span> <span class="s2">&#34;school&#34;</span><span class="p">;</span>
    <span class="nx">Person</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">arr</span> <span class="o">=</span> <span class="p">[];</span>

    <span class="kd">var</span> <span class="nx">person1</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;xiaoming&#34;</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">person2</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;Jc&#34;</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;原始类型&#34;</span><span class="p">)</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">position</span><span class="p">);</span> <span class="c1">// &#34;school&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">position</span><span class="p">);</span> <span class="c1">// &#34;school&#34;
</span><span class="c1"></span>
    <span class="nx">person1</span><span class="p">.</span><span class="nx">position</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// 这是在当前属性设置position，引用类型同理
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;position&#34;</span><span class="p">));</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;position&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;引用类型&#34;</span><span class="p">);</span>
    <span class="nx">person1</span><span class="p">.</span><span class="nx">arr</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">&#34;pizza&#34;</span><span class="p">);</span> <span class="c1">// 这是在原型对象上设置，而不是直接在对象上
</span><span class="c1"></span>    <span class="nx">person2</span><span class="p">.</span><span class="nx">arr</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">&#34;quinoa&#34;</span><span class="p">);</span> <span class="c1">// 这是在原型对象上设置
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;arr&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;arr&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">arr</span><span class="p">);</span> <span class="c1">// [&#34;pizza&#34;, &#34;quinoa&#34;]
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">arr</span><span class="p">);</span> <span class="c1">// [&#34;pizza&#34;, &#34;quinoa&#34;]
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>上面是在原型对象上一一添加属性，下面一种更简洁的方式：以一个对象字面形式替换原型对象</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">name</span>
    <span class="p">}</span>
    
    <span class="nx">Person</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">sayName</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
        <span class="p">},</span>
        <span class="nx">toString</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="k">return</span> <span class="s2">&#34;[Person ]&#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">&#34;]&#34;</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>


</code></pre></td></tr></table>
</div>
</div><p>这种方式有一种副作用：因为原型对象上具有一个 <code>constructor</code> 属性，这是其他对象实例所没有的。当一个函数被创建时，它的  <code>prototype</code> 属性也会被创建，且该原型对象的 <code>constructor</code> 属性指向该函数。当使用字面量时，因没显式设置原型对象的 <code>constructor</code> 属性，因此其 <code>constructor</code> 属性是指向 <code>Object</code> 的。
因此，当通过此方式设置原型对象时，可手动设置 <code>constructor</code> 属性。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">name</span>
    <span class="p">}</span>
    
    <span class="c1">// 建议第一个属性就是设置其 constructor 属性。
</span><span class="c1"></span>    <span class="nx">Person</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">constructor</span><span class="o">:</span> <span class="nx">Person</span><span class="p">,</span>
    
        <span class="nx">sayName</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
        <span class="p">},</span>
        <span class="nx">toString</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="k">return</span> <span class="s2">&#34;[Person ]&#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">&#34;]&#34;</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>构造函数、原型对象和对象实例之间的关系最有趣的一方面也许是：
对象实例和构造函数直接没有直接联系。（对象实例只有 <code>[[Prototype]]</code> 属性指向其相应的原型对象，而原型对象的 <code>constructor</code> 属性指向构造函数，而构造函数的 <code>prototype</code> 指向原型对象）
![obj_constructor_prototype][5]</p>
<h4 id="423-改变原型对象">4.2.3 改变原型对象</h4>
<p>因为每个对象的 <code>[[Prototype]]</code> 只是一个指向原型对象的指针，所以原型对象的改动会立刻反映到所有引用它的对象。
当对一个对象使用封印 <code>Object.seal()</code> 或冻结 <code>Object.freeze()</code> 时，完全是在操作对象的自有属性，但任然可以通过在原型对象上添加属性来扩展这些对象实例。</p>
<h4 id="424-内建对象如arraystring的原型对象">4.2.4 内建对象（如Array、String）的原型对象</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="nb">String</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">capitalize</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><h3 id="总结">总结</h3>
<ul>
<li>构造函数就是用 <code>new</code> 操作符调用的普通函数。可用过 <code>instanceof</code> 操作符或直接访问 <code>constructor</code>(实际上是原型对象的属性) 来鉴别对象是被哪个构造函数所创建的。</li>
<li>每个函数都有一个 <code>prototype</code> 对象，它定义了该构造函数创建的所有对象共享的属性。而 <code>constructor</code> 属性实际上是定义在原型对象里，供所有对象实例共享。</li>
<li>每个对象实例都有 <code>[[Prototype]]</code> 属性，它是指向原型对象的指针。当访问对象的某个属性时，先从对象自身查找，找不到的话就到原型对象上找。</li>
<li>内建对象的原型对象也可被修改</li>
</ul>
<h2 id="5-继承">5. 继承</h2>
<h3 id="51-原型对象链和-objectprototype">5.1 原型对象链和 Object.prototype</h3>
<p>JavaScript内建的继承方法被称为 原型对象链（又叫原型对象继承）。
原型对象的属性可经由对象实例访问，这就是继承的一种形式。对象实例继承了原型对象的属性，而原型对象也是一个对象，它也有自己的原型对象并继承其属性，以此类推。这就是原型对象链。</p>
<p>所有对象（包括自义定的）都自动继承自 <code>Object</code>，除非你另有指定。更确切地说，所有对象都继承自 <code>Object.prototype</code>。任何以对象字面量形式定义的对象，其 <code>[[Prototype]]</code> 的值都被设为 <code>Object.prototype</code>，这意味着它继承 <code>Object.prototype</code> 的属性。</p>
<h4 id="511-继承自-objectprototype-的方法">5.1.1 继承自 Object.prototype 的方法</h4>
<p>Object.prototype 一般有以下几个方法</p>
<ul>
<li>hasOwnProperty()             检测是否存在一个给定名字的自有属性</li>
<li>propertyIsemumerable()       检查一个自有属性是否可枚举</li>
<li>isPrototypeOf                检查一个对象是否是另一个对象的原型对象</li>
<li>valueOf()                    返回一个对象的值表达</li>
<li>toString()                   返回一个对象的字符串表达</li>
</ul>
<p>这 5 种方法经由继承出现在所有对象中。
因为所有对象都默认继承自 <code>Object.prototype</code>，所以改变它就会影响所有的对象。所以不建议。</p>
<h3 id="52-继承">5.2 继承</h3>
<p>对象继承是最简单的继承类型。你唯需要做的是指定哪个对象是新对象的 <code>[[Prototype]]</code>。对象字面量形式会隐式指定 <code>Object.prototype</code> 为其 <code>[[Protoype]]</code>。当然我们可以用 ES5 的 <code>Object.create()</code> 方法显式指定。该方法接受两个参数，第一个是新对象的的 <code>[[Prototype]]</code> 所指向的对象。第二个参数是可选的一个属性描述对象，其格式与 <code>Object.definePrototies()</code>一样。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Ljc&#34;</span>
    <span class="p">};</span>
    
    <span class="c1">// 等同于
</span><span class="c1"></span>    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;Ljc&#34;</span><span class="p">,</span>
            <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">enumberable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span>
        <span class="p">}</span>
    <span class="p">});</span>

</code></pre></td></tr></table>
</div>
</div><p>下面是继承其它对象：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Jack&#34;</span><span class="p">,</span>
        <span class="nx">sayName</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    
    <span class="kd">var</span> <span class="nx">student</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">name</span><span class="o">:</span><span class="p">{</span>
            <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;Ljc&#34;</span>
        <span class="p">},</span>
        <span class="nx">grade</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;fourth year of university&#34;</span><span class="p">,</span>
            <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span>
        <span class="p">}</span>
    <span class="p">});</span>
    
    <span class="nx">person</span><span class="p">.</span><span class="nx">sayName</span><span class="p">();</span> <span class="c1">// &#34;Jack&#34;
</span><span class="c1"></span>    <span class="nx">student</span><span class="p">.</span><span class="nx">sayName</span><span class="p">();</span> <span class="c1">// &#34;Ljc&#34;
</span><span class="c1"></span>    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;sayName&#34;</span><span class="p">));</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">isPrototypeOf</span><span class="p">(</span><span class="nx">student</span><span class="p">));</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">student</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="s2">&#34;sayName&#34;</span><span class="p">));</span> <span class="c1">// false
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;sayName&#34;</span> <span class="k">in</span> <span class="nx">student</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>![对象继承][6]</p>
<p>当访问一个对象属性时，JavaScript引擎会执行一个搜索过程。如果在对象实例存在该自有属性，则返回，否则，根据其私有属性 <code>[[Protoype]]</code> 所指向的原型对象进行搜索，找到返回，否则继承上述操作，知道继承链末端。末端通常是 <code>Object.prototype</code>，其 <code>[[Prototype]]</code> 是 <code>null</code>。</p>
<p>当然，也可以用 <code>Object.create()</code> 常见一个 <code>[[Prototype]]</code> 为 <code>null</code> 的对象。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">obj</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;toString&#34;</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">);</span> <span class="c1">// false
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>该对象是一个没有原型对象链的对象，即是一个没有预定义属性的白板。</p>
<h3 id="53-构造函数继承">5.3 构造函数继承</h3>
<p>JavaScript 中的对象继承也是构造函数继承的基础。
第四章提到，几乎所有函数都有 <code>prototype</code> 属性，它可被修改或替换。该 <code>prototype</code> 属性被自动设置为一个新的继承自 <code>Object.prototype</code> 的泛用对象，该对象(原型对象)有一个自有属性 <code>constructor</code>。实际上，JavaScript 引擎为你做了下面的事情。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="c1">// 你写成这样
</span><span class="c1"></span>    <span class="kd">function</span> <span class="nx">YourConstructor</span><span class="p">(){</span>
        <span class="c1">// initialization
</span><span class="c1"></span>    <span class="p">}</span>
    
    <span class="c1">// JavaScript引擎在背后为你做了这些处理
</span><span class="c1"></span>    <span class="nx">YourConstructor</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">constructor</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">value</span><span class="o">:</span> <span class="nx">YourConstructor</span><span class="p">,</span>
            <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span>
        <span class="p">}</span>
    <span class="p">})</span>

</code></pre></td></tr></table>
</div>
</div><p>你不需要做额外的工作，这段代码帮你把构造函数的 <code>prototype</code> 属性设置为一个继承自 <code>Object.prototype</code> 的对象。这意味着 <code>YourConstructor</code> 创建出来的任何对象都继承自 <code>Object.prototype</code>。</p>
<p>由于 prototype 可写，你可以通过改变它来改变原型对象链。</p>
<blockquote>
<p>MDN:instanceof 运算符可以用来判断某个构造函数的 prototype 属性是否存在另外一个要检测对象的原型链上。</p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">Rectangle</span><span class="p">(</span><span class="nx">length</span><span class="p">,</span> <span class="nx">width</span><span class="p">){</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="nx">length</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">width</span>
    <span class="p">}</span>

    <span class="nx">Rectangle</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">getArea</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">length</span> <span class="o">*</span> <span class="k">this</span><span class="p">.</span><span class="nx">width</span>
    <span class="p">}</span>

    <span class="nx">Rectangle</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="k">return</span> <span class="s2">&#34;[Rectangle &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="s2">&#34;x&#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">+</span> <span class="s2">&#34;]&#34;</span><span class="p">;</span>
    <span class="p">}</span>


    <span class="c1">// inherits from Rectangle
</span><span class="c1"></span>    <span class="kd">function</span> <span class="nx">Square</span><span class="p">(</span><span class="nx">size</span><span class="p">){</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="nx">size</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">size</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">Square</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Rectangle</span><span class="p">();</span> <span class="c1">// 尽管是 Square.prototype 是指向了 Rectangle 的对象实例，即Square的实例对象也能访问该实例的属性（如果你提前声明了该对象，且给该对象新增属性）。
</span><span class="c1"></span>    <span class="c1">// Square.prototype = Rectangle.prototype; // 这种实现没有上面这种好，因为Square.prototype 指向了 Rectangle.prototype，导致修改Square.prototype时，实际就是修改Rectangle.prototype。
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Square</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">constructor</span><span class="p">);</span> <span class="c1">// 输出 Rectangle 构造函数
</span><span class="c1"></span>
    <span class="nx">Square</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">constructor</span> <span class="o">=</span> <span class="nx">Square</span><span class="p">;</span> <span class="c1">// 重置回 Square 构造函数
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">Square</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">constructor</span><span class="p">);</span> <span class="c1">// 输出 Square 构造函数
</span><span class="c1"></span>
    <span class="nx">Square</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
        <span class="k">return</span> <span class="s2">&#34;[Square &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="s2">&#34;x&#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">+</span> <span class="s2">&#34;]&#34;</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">var</span> <span class="nx">rect</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Rectangle</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">square</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Square</span><span class="p">(</span><span class="mi">6</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">rect</span><span class="p">.</span><span class="nx">getArea</span><span class="p">());</span> <span class="c1">// 50
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span><span class="p">.</span><span class="nx">getArea</span><span class="p">());</span> <span class="c1">// 36
</span><span class="c1"></span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">rect</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="c1">// &#34;[Rectangle 5 * 10]&#34;, 但如果是Square.prototype = Rectangle.prototype，则这里会&#34;[Square 5 * 10]&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="c1">// &#34;[Square 6 * 6]&#34;
</span><span class="c1"></span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span> <span class="k">instanceof</span> <span class="nx">Square</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span> <span class="k">instanceof</span> <span class="nx">Rectangle</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">square</span> <span class="k">instanceof</span> <span class="nb">Object</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>    
</code></pre></td></tr></table>
</div>
</div><p>![构造函数继承][7]</p>
<p><code>Square.prototype</code> 并不真的需要被改成为一个 <code>Rectangle</code> 对象。事实上，是 <code>Square.prototype</code> 需要指向 <code>Rectangle.prototype</code> 使得继承得以实现。这意味着可以用 <code>Object.create()</code> 简化例子。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="c1">// inherits from Rectangle
</span><span class="c1"></span>    <span class="kd">function</span> <span class="nx">Square</span><span class="p">(</span><span class="nx">size</span><span class="p">){</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="nx">size</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">size</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="nx">Square</span><span class="p">.</span><span class="nx">prototype</span><span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">Rectangle</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
        <span class="nx">constructor</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">configurable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">enumerable</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
            <span class="nx">value</span><span class="o">:</span> <span class="nx">Square</span><span class="p">,</span>
            <span class="nx">writable</span><span class="o">:</span> <span class="kc">true</span>
        <span class="p">}</span>
    <span class="p">})</span>


</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>在对原型对象添加属性前要确保你已经改成了原型对象，否则在改写时会丢失之前添加的方法（因为继承是将被继承对象赋值给需要继承的原型对象，相当于重写了需要继承的原型对象）。</p>
</blockquote>
<h3 id="54-构造函数窃取">5.4 构造函数窃取</h3>
<p>由于JavaScript中的继承是通过原型对象链来实现的，因此不需要调用对象的父类的构造函数。如果确实需要在子类构造函数中调用父类构造函数，那就可以在子类的构造函数中利用 <code>call</code>、<code>apply</code>方法调用父类的构造函数。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="c1">// 在上面的代码基础上作出修改
</span><span class="c1"></span>    <span class="c1">// inherits from Rectangle
</span><span class="c1"></span>    <span class="kd">function</span> <span class="nx">Square</span><span class="p">(</span><span class="nx">size</span><span class="p">){</span>
        <span class="nx">Rectangle</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">size</span><span class="p">);</span>
        
        <span class="c1">// optional: add new properties or override existing ones here
</span><span class="c1"></span>    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>一般来说，需要修改 <code>prototyp</code> 来继承方法并用构造函数窃取来设置属性，由于这种做法模仿了那些基于类的语言的类继承，所以这通常被称为伪类继承。</p>
<h3 id="55-访问父类方法">5.5 访问父类方法</h3>
<p>其实也是通过指定 <code>call</code> 或 <code>apply</code> 的子对象调用父类方法。</p>
<h2 id="6-对象模式">6 对象模式</h2>
<p>###6.1 私有成员和特权成员
JavaScipt 对象的所有属性都是公有的，没有显式的方法指定某个属性不能被外界访问。</p>
<h4 id="611-模块模式">6.1.1 模块模式</h4>
<p>模块模式是一种用于创建<strong>拥有私有数据的单件对象</strong>的模式。
基本做法是使用立即调用函数表达式（IIFE）来返回一个对象。原理是利用闭包。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">yourObj</span> <span class="o">=</span> <span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
        <span class="c1">// private data variables
</span><span class="c1"></span>        
        <span class="k">return</span> <span class="p">{</span>
            <span class="c1">// public methods and properties
</span><span class="c1"></span>        <span class="p">}</span>
    <span class="p">}());</span>

</code></pre></td></tr></table>
</div>
</div><p>模块模式还有一个变种叫暴露模块模式，它将所有的变量和方法都放在 <code>IIFE</code> 的头部，然后将它们设置到需要被返回的对象上。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="c1">//  一般写法
</span><span class="c1"></span>    <span class="kd">var</span> <span class="nx">yourObj</span> <span class="o">=</span> <span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
        <span class="kd">var</span> <span class="nx">age</span> <span class="o">=</span> <span class="mi">25</span><span class="p">;</span>
        
        <span class="k">return</span> <span class="p">{</span>
            <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Ljc&#34;</span><span class="p">,</span>
            
            <span class="nx">getAge</span><span class="o">:</span> <span class="kd">function</span><span class="p">(){</span>
                <span class="k">return</span> <span class="nx">agel</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}());</span>
    
    <span class="c1">// 暴露模块模式
</span><span class="c1"></span>    <span class="kd">var</span> <span class="nx">yourObj</span> <span class="o">=</span> <span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
        <span class="kd">var</span> <span class="nx">age</span> <span class="o">=</span> <span class="mi">25</span><span class="p">;</span>
        <span class="kd">function</span> <span class="nx">getAge</span><span class="p">(){</span>
            <span class="k">return</span> <span class="nx">agel</span>
        <span class="p">};</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Ljc&#34;</span><span class="p">,</span>
            <span class="nx">getAge</span><span class="o">:</span> <span class="nx">getAge</span>
        <span class="p">}</span>
    <span class="p">}());</span>

</code></pre></td></tr></table>
</div>
</div><h4 id="612-构造函数的私有成员不能通过对象直接访问">6.1.2 构造函数的私有成员（不能通过对象直接访问）</h4>
<p>模块模式在定义单个对象的私有属性十分有效，但对于那些同样需要私有属性的自定义类型呢？你可以在构造函数中使用类似的模式来创建每个实例的私有数据。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
        <span class="c1">// define a variable only accessible inside of the Person constructor
</span><span class="c1"></span>        <span class="kd">var</span> <span class="nx">age</span> <span class="o">=</span> <span class="mi">22</span><span class="p">;</span>
        
        <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">getAge</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="k">return</span> <span class="nx">age</span><span class="p">;</span>
        <span class="p">};</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">growOlder</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="nx">age</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    
    <span class="kd">var</span> <span class="nx">person</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;Ljc&#34;</span><span class="p">);</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">age</span><span class="p">);</span> <span class="c1">// undefined
</span><span class="c1"></span>    <span class="nx">person</span><span class="p">.</span><span class="nx">age</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">getAge</span><span class="p">());</span> <span class="c1">// 22
</span><span class="c1"></span>    
    <span class="nx">person</span><span class="p">.</span><span class="nx">growOlder</span><span class="p">();</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person</span><span class="p">.</span><span class="nx">getAge</span><span class="p">());</span> <span class="c1">// 23
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><p>这里有个问题：如果你需要<strong>对象实例</strong>拥有私有数据，就不能将相应方法放在 <code>prototype</code> 上。</p>
<p>如果你需要所有实例共享私有数据。则可结合模块模式和构造函数，如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">var</span> <span class="nx">Person</span> <span class="o">=</span> <span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
        <span class="kd">var</span> <span class="nx">age</span> <span class="o">=</span> <span class="mi">22</span><span class="p">;</span>

        <span class="kd">function</span> <span class="nx">InnerPerson</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="nx">InnerPerson</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">getAge</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="k">return</span> <span class="nx">age</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="nx">InnerPerson</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">growOlder</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
            <span class="nx">age</span><span class="o">++</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nx">InnerPerson</span><span class="p">;</span>
    <span class="p">}());</span>

    <span class="kd">var</span> <span class="nx">person1</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;Nicholash&#34;</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">person2</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;Greg&#34;</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// &#34;Nicholash&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">getAge</span><span class="p">());</span> <span class="c1">// 22
</span><span class="c1"></span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// &#34;Greg&#34;
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">getAge</span><span class="p">());</span> <span class="c1">// 22
</span><span class="c1"></span>
    <span class="nx">person1</span><span class="p">.</span><span class="nx">growOlder</span><span class="p">();</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person1</span><span class="p">.</span><span class="nx">getAge</span><span class="p">());</span> <span class="c1">// 23
</span><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">person2</span><span class="p">.</span><span class="nx">getAge</span><span class="p">());</span> <span class="c1">// 23
</span><span class="c1"></span>
</code></pre></td></tr></table>
</div>
</div><h3 id="62-混入">6.2 混入</h3>
<p>这是一种伪继承。一个对象在不改变原型对象链的情况下得到了另外一个对象的属性被称为“混入”。因此，和继承不同，混入让你在创建对象后无法检查属性来源。
纯函数实现：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">mixin</span><span class="p">(</span><span class="nx">receiver</span><span class="p">,</span> <span class="nx">supplier</span><span class="p">){</span>
        <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">property</span> <span class="k">in</span> <span class="nx">supplier</span><span class="p">){</span>
            <span class="k">if</span><span class="p">(</span><span class="nx">supplier</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="nx">property</span><span class="p">)){</span>
                <span class="nx">receiver</span><span class="p">[</span><span class="nx">property</span><span class="p">]</span> <span class="o">=</span> <span class="nx">supplier</span><span class="p">[</span><span class="nx">property</span><span class="p">];</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>这是浅拷贝，如果属性的值是一个引用，那么两者将指向同一个对象。</p>
<h3 id="63-作用域安全的构造函数">6.3 作用域安全的构造函数</h3>
<p>构造函数也是函数，所以不用 new 也能调用它们来改变 <code>this</code> 的值。在非严格模式下， <code>this</code> 被强制指向全局对象。而在严格模式下，构造函数会抛出一个错误（因为严格模式下没有为全局对象设置 <code>this</code>，<code>this</code> 保持为 <code>undefined</code>）。
而很多内建构造函数，例如 <code>Array</code>、<code>RegExp</code> 不需要 <code>new</code> 也能正常工作，这是因为它们被设计为作用域安全的构造函数。
当用 <code>new</code> 调用一个函数时，<code>this</code> 指向的新创建的对象是属于该构造函数所代表的自定义类型。因此，可在函数内用 <code>instanceof</code> 检查自己是否被 <code>new</code> 调用。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">
    <span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
        <span class="k">if</span><span class="p">(</span><span class="k">this</span> <span class="k">instanceof</span> <span class="nx">Person</span><span class="p">){</span>
            <span class="c1">// called with &#34;new&#34;
</span><span class="c1"></span>        <span class="p">}</span><span class="k">else</span><span class="p">{</span>
            <span class="c1">// called without &#34;new&#34;
</span><span class="c1"></span>        <span class="p">}</span>
    <span class="p">}</span>

</code></pre></td></tr></table>
</div>
</div><p>具体案例：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript">    <span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
        <span class="k">if</span><span class="p">(</span><span class="k">this</span> <span class="k">instanceof</span> <span class="nx">Person</span><span class="p">){</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
        <span class="p">}</span><span class="k">else</span><span class="p">{</span>
            <span class="k">return</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div>
    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">even</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2017-08-12
        
    </span>
  </p>
  
  
</div>
<footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">读书笔记</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/htmlcss/%E5%B1%8F%E5%B9%95%E8%AE%BE%E5%A4%87%E7%9A%84%E4%B8%80%E4%BA%9B%E6%A6%82%E5%BF%B5/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">屏幕设备的一些概念</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/javascript/jquery%E5%B8%B8%E7%94%A8%E6%93%8D%E4%BD%9C/">
            <span class="next-text nav-default">jQuery常用操作</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:your@email.com" class="iconfont icon-email" title="email"></a>
      <a href="http://localhost:1313" class="iconfont icon-stack-overflow" title="stack-overflow"></a>
      <a href="http://localhost:1313" class="iconfont icon-twitter" title="twitter"></a>
      <a href="http://localhost:1313" class="iconfont icon-facebook" title="facebook"></a>
      <a href="http://localhost:1313" class="iconfont icon-linkedin" title="linkedin"></a>
      <a href="http://localhost:1313" class="iconfont icon-google" title="google"></a>
      <a href="http://localhost:1313" class="iconfont icon-github" title="github"></a>
      <a href="http://localhost:1313" class="iconfont icon-weibo" title="weibo"></a>
      <a href="http://localhost:1313" class="iconfont icon-zhihu" title="zhihu"></a>
      <a href="http://localhost:1313" class="iconfont icon-douban" title="douban"></a>
      <a href="http://localhost:1313" class="iconfont icon-pocket" title="pocket"></a>
      <a href="http://localhost:1313" class="iconfont icon-tumblr" title="tumblr"></a>
      <a href="http://localhost:1313" class="iconfont icon-instagram" title="instagram"></a>
      <a href="http://localhost:1313" class="iconfont icon-gitlab" title="gitlab"></a>
      <a href="http://localhost:1313" class="iconfont icon-bilibili" title="bilibili"></a>
  <a href="https://zhouxiaoxin.gitee.io/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>

<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  <div class="busuanzi-footer">
    <span id="busuanzi_container_site_pv"> 本站总访问量 <span id="busuanzi_value_site_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次 </span>
      <span class="division">|</span>
    <span id="busuanzi_container_site_uv"> 本站总访客数 <span id="busuanzi_value_site_uv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 人 </span>
  </div>

  <span class="copyright-year">
    &copy; 
    2018 - 
    2022
    <span class="heart">
      <i class="iconfont icon-heart"></i>
    </span>
    <span class="author">even</span>
  </span>
</div>
    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.2517c0eb67172a0bae917de4af59b10ca2531411a009d4c0b82f5685259e5771.js"></script>








</body>
</html>
